const router=require('koa-router')();
const koaBody=require('koa-body');
const events=require('events');
const _=require('underscore');
const moment=require('moment');
const config=require('../config/config');
const {Post,User,Comment,Archive,Message}=require('../models/index');
const redis=require('../models/redis.server.model');
const postProxy=require('../proxy/index').post;
const checkId=require('../middlewares/checkId');
const checkToken=require('../middlewares/checkToken');
const apiIpLimit=require('../middlewares/apiIpLimit');
const apiTokenLimit=require('../middlewares/apiTokenLimit');
const checkPostAuth=require('../middlewares/checkPostAuth');
const verifyPost=require('../lib/verifyPost');

//主题首页
router.get('/topics',apiIpLimit({action:'getTopics'}),async ctx=>{
    let [{posts}]=await Promise.all([
        postProxy.getAPIPosts(null,null,{page:ctx.query.p,limit:ctx.query.limit}),
        await redis.addLimit({action:'getTopics',id:ctx.request.ip})
    ]);
    ctx.body={
        code:200,
        data:posts
    };
});

//主题详情
router.get('/topic/:id',checkId(),apiIpLimit({action:'getTopic'}),async ctx=>{
    let [post]=await Promise.all([
        Post.findOne({_id:ctx.params.id},{archive:false,reprintUsers:false,__v:false}),
        await redis.addLimit({action:'getTopic',id:ctx.request.ip})
    ]);

    if(!post)return ctx.body={code:404,msg:'话题不存在或已经删除'};

    let author=await User.findOne({_id:post.author},{_id:true,name:true,email:true,avatar:true});

    let data=_.pick(post,'_id','title','tags','intro','content','time','pv');
    data.author={
        name:author.name,
        avatar_url:config.avatarCDN+'/'+author.avatar+'?v=3&s=120'
    };
    ctx.body={
        code:200,
        data
    };
});


//获取标签列表
router.get('/tags',apiIpLimit({action:'getTagList'}),async ctx=>{
    await redis.addLimit({action:'getTagList',id:ctx.request.ip})
    ctx.body={
        code:200,
        data:{
            tags:config.post.tags
        }
    };
});
//获取当前标签下的话题，支持翻页
router.get('/tags/:tag',apiIpLimit({action:'getTagTopics'}),async ctx=>{
    let {tag}=ctx.params,tags=config.post.tags;
    if(!~tags.indexOf(tag))return ctx.body={code:404,msg:'标签不存在'};
    let [{posts}]=await Promise.all([
        postProxy.getAPIPosts({tags:{$in:[tag]}},null,{page:ctx.query.p,limit:ctx.query.limit}),
        await redis.addLimit({action:'getTagTopics',id:ctx.request.ip})
    ]);

    ctx.body={
        code:200,
        data:posts
    };
});

//获取日期归档列表
router.get('/archives',apiIpLimit({action:'getArchiveList'}),async ctx=>{
    let [archives]=await Promise.all([
        Archive.find({},{archive:true,count:true}),
        await redis.addLimit({action:'getArchiveList',id:ctx.request.ip})
    ]);
    ctx.body={
        code:200,
        data:archives
    }
});
//获取当前归档下的话题列表，支持翻页
router.get('/archives/:date',apiIpLimit({actin:'getArchiveTopics'}),async ctx=>{
    let {date}=ctx.params,ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    if(!/2\d{3}\-\d{2}/.test(date) || Number.isNaN(new Date(date)))return ee.emit('fail','日期非法');

    let [{posts}]=await Promise.all([
        postProxy.getAPIPosts({archive:date},null,{page:ctx.query.p,limit:ctx.query.limit}),
        redis.addLimit({action:'getArchiveTopics',id:ctx.request.ip})
    ]);

    ctx.body={
        code:200,
        data:posts
    };
});


//发表话题
router.post('/topic',checkToken(),apiTokenLimit({action:'newTopic'}),koaBody(),async ctx=>{
    let {token,tokenUser}=ctx.state,{body}=ctx.request,ee=new events();
    ee.on('invalid',msg=>{
        ctx.body={
            code:400,
            msg
        }
    });
    let verifyPostRet=verifyPost(body);
    if(verifyPostRet)return ee.emit('invalid',verifyPostRet);

    let time=new Date(),archive=moment(time).format('YYYY-MM');

    let [post]=await Promise.all([
        new Post({
            title:body.title,
            tags:body.tags,
            intro:body.intro,
            content:body.content,
            author:tokenUser._id,
            time,
            archive
        }).save(),
        User.update({token},{$inc:{score:config.score.post}}),
        Archive.update({archive},{$inc:{count:1}},{upsert:true}),
        redis.addLimit({action:'newTopic',id:token})
    ]);

    ctx.body={
        code:200,
        msg:'success',
        topic_id:post._id
    };
});

//编辑话题
router.patch('/edit/topic/:id',checkId(),checkToken(),apiTokenLimit({action:'editTopic'}),checkPostAuth(),koaBody(),async ctx=>{
    let {id,token,tokenUser,post}=ctx.state,{body}=ctx.request,ee=new events();
    ee.on('invalid',msg=>{
        ctx.body={
            code:400,
            msg
        }
    });

    let data={
        title:body.title || post.title,
        tags:body.tags || post.tags,
        intro:body.intro || post.intro,
        content:body.content || post.content
    };
    let verifyPostRet=verifyPost(data);
    if(verifyPostRet)return ee.emit('invalid',verifyPostRet);

    await Promise.all([
        Post.update({_id:id},data),
        redis.addLimit({action:'editTopic',id:token})
    ]);

    ctx.body={
        code:200,
        msg:'success',
        topic_id:id
    };
});

//收藏主题
router.post('/collect/topic/:id',checkId(),apiTokenLimit({'action':'collectTopic'}),checkPostAuth({verify:false}),async ctx=>{
    let {token,tokenUser,post}=ctx.state;
    await Promise.all([
        User.update({_id:tokenUser},{$addToSet:{collections:post._id}}),
        redis.addLimit({action:'collectTopic',id:token})
    ]);
    ctx.body={
        code:200,
        msg:'success'
    };
});

//取消收藏主题
router.post('/de_collect/topic/:id',checkId(),apiTokenLimit({'action':'de_collectTopic'}),checkPostAuth({verify:false}),async ctx=>{
    let {token,tokenUser,post}=ctx.state;
    await Promise.all([
        User.update({_id:tokenUser},{$pull:{collections:post._id}}),
        redis.addLimit({action:'de_collectTopic',id:token})
    ]);
    ctx.body={
        code:200,
        msg:'success'
    };
});

//用户收藏的所有主题，支持翻页
router.get('/collections/:name',apiTokenLimit({action:'getUserCollections'}),async ctx=>{
    let {token}=ctx.query,{name}=ctx.params,ee=new events();
    let [tokenUser,collectionUser]=await Promise.all([
        User.findOne({token}),
        User.findOne({name},{collections:true})
    ]);
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    if(!tokenUser || !collectionUser)return ee.emit('fail','Token错误或用户不存在');

    let [{posts}]=await Promise.all([
        postProxy.getAPIPosts({_id:{$in:collectionUser.collections}},null,{page:ctx.query.p,limit:ctx.query.limit}),
        redis.addLimit({action:'getUserCollections',id:token})
    ]);

    ctx.body={
        code:200,
        data:posts
    };
});

//评论话题
router.post('/comment/topic/:id',checkId(),apiTokenLimit({action:'comment'}),checkPostAuth(false),koaBody(),async ctx=>{
    let {id,token,tokenUser,post}=ctx.state,{content}=ctx.request.body;
    let ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    if(!content || content.length<config.characterLengthLimit.post.comment[0] || content.length>config.characterLengthLimit.post.comment[1])return ee.emit('fail',`评论内容长度非法(${config.characterLengthLimit.post.comment[0]}~${config.characterLengthLimit.post.comment[1]})`);

    let comment=new Comment({
        content,
        post:id,
        author:tokenUser,
        time:new Date()
    });
    await Promise.all([
        Post.update({_id:post._id},{$push:{comments:comment._id}}),
        User.update({token},{$inc:{score:config.score.comment}}),
        comment.save(),
        redis.addLimit({action:'comment',id:token})
    ]);
    ctx.body={
        code:200,
        msg:'Success',
        reply_id:comment._id
    };
});

//回复评论
router.post('/reply/:id',checkId(),apiTokenLimit({action:'reply'}),koaBody(),async ctx=>{
    let {token}=ctx.query,{id}=ctx.params,{content}=ctx.request.body,ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    if(!content || content.trim().length<config.characterLengthLimit.post.comment[0] || content.trim().length>config.characterLengthLimit.post.comment[1])return ee.emit('fail',`回复内容长度非法(${config.characterLengthLimit.post.comment[0]}~${config.characterLengthLimit.post.comment[1]})`);

    let [tokenUser,comment]=await Promise.all([
        User.findOne({token}),
        Comment.findOne({_id:id},{author:true,post:true})
    ]);
    if(!tokenUser || !comment)return ee.emit('fail','Token或评论不存在');

    let [post,commentAuthor]=await Promise.all([
        Post.findOne({_id:comment.post}),
        User.findOne({_id:comment.author},{name:true})
    ]);

    if(!post)return ee.emit('fail','话题不存在');

    let newComment=new Comment({
        content,
        post:post._id,
        author:tokenUser._id,
        atUser:{
            _id:commentAuthor._id,
            name:commentAuthor.name
        },
        time:new Date
    });

    let tasks=[
        newComment.save(),
        Post.update({_id:post},{$push:{comments:newComment._id}}),
        redis.addLimit({action:'reply',id:token})
    ];
    if(comment.author.toString()!==tokenUser._id.toString()){
        tasks.push(User.update({token},{$inc:{score:config.score.comment}}))
    }

    await Promise.all(tasks);

    ctx.body={
        code:200,
        msg:'success',
        reply_id:newComment._id
    };
});


//为评论点赞
router.post('/ups/:id',checkId(),apiTokenLimit({action:'ups'}),async ctx=>{
    let {id}=ctx.params,{token}=ctx.query,action;
    let [tokenUser,comment]=await Promise.all([
        User.findOne({token}),
        Comment.findOne({_id:id},{ups:true})
    ]);
    if(!tokenUser || !comment)return ctx.body={code:400,msg:'Token错误或评论不存在'};

    let ups=comment.ups;
    if(ups.find(up=>up.toString()==tokenUser._id.toString())){//取消赞
        action='down';
        await Comment.update({_id:id},{$pull:{ups:tokenUser._id}});
    }else{//点赞
        action='up';
        await Comment.update({_id:id},{$addToSet:{ups:tokenUser._id}});
    }

    ctx.body={
        code:200,
        msg:'success',
        action
    };
});

//获取用户详情
router.get('/user/:id',checkId(),apiTokenLimit({action:'getUser'}),async ctx=>{
    let {id}=ctx.params,{token}=ctx.query,ee=new events;
    let [tokenUser,user]=await Promise.all([
        User.findOne({token}),
        User.findOne({_id:id},{name:true,email:true,avatar:true,regTime:true,score:true}),
        redis.addLimit({action:'getUser',id:token})
    ]);
    ee.on('fail',msg=>{
       ctx.body={
           code:400,
           msg
       }
    });

    if(!tokenUser || !user)return ee.emit('Token错误或用户不存在');

    let data=_.pick(user,'name','retTime','email','score');
    data.avatar_url=config.avatarCDN+'/'+user.avatar+'?v=3&s=120';

    let {posts}=await postProxy.getAPIPosts({author:user._id},null,{page:ctx.query.p});

    ctx.body={
        code:200,
        data:{user,posts}
    };
});


//message
//--获取未读消息数
router.get('/message/count',apiTokenLimit({action:'getMessageCount'}),async ctx=>{
    let {token}=ctx.query,ee=new events();
    let [tokenUser]=await Promise.all([
        User.findOne({token}),
        redis.addLimit({action:'getMessageCount',id:token})
    ]);
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    if(!tokenUser)return ee.emit('fail','Token错误');

    let count=await Message.count({to:tokenUser._id});

    ctx.body={
        code:200,
        data:count
    };
});

//--获取已读和未读消息
router.get('/messages',apiTokenLimit({action:'getMessages'}),async ctx=>{
   let {token}=ctx.query,ee=new events();
   let [tokenUser]=await Promise.all([
       User.findOne({token}),
       redis.addLimit({actin:'getMessages',id:token})
   ]);
   ee.on('fail',msg=>{
       ctx.body={
           code:400,
           msg
       };
   });

   if(!tokenUser)return ee.emit('fail','Token错误');

   let messages=await Message.find({to:tokenUser._id},{__v:false});

   let has_read=[],hasnot_read=[];
   messages.forEach(msg=>{
       if(msg.read)has_read.push(msg);
       else hasnot_read.push(msg);
       delete msg.read;
   });

   ctx.body={
       code:200,
       data:{
           has_read,
           hasnot_read
       }
   };
});

//--标记全部消息为已读
router.post('/message/mark_all',apiTokenLimit({action:'markAll'}),async ctx=>{
    let {token}=ctx.query,ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    let [tokenUser]=await Promise.all([
        User.findOne({token}),
        redis.addLimit({action:'markAll',id:token})
    ]);
    if(!tokenUser)return ee.emit('Token错误');

    let ret=await Message.find({read:false},{_id:true});
    let ids=ret.map(doc=>doc._id);
    await Message.update({_id:{$in:ids}},{read:true},{multi:true});

    ctx.body={
        code:200,
        marked_msgs:ids
    };
});
//--标记单个消息为已读
router.post('/message/mark_one/:id',checkId(),apiTokenLimit({action:'markOne'}),async ctx=>{
    let {token}=ctx.query,{id}=ctx.params,ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            code:400,
            msg
        };
    });

    let [tokenUser]=await Promise.all([
        User.findOne({token}),
        redis.addLimit({action:'markOne',id:token})
    ]);
    if(!tokenUser)return ee.emit('fail','Token错误');

    await Message.update({_id:id},{$set:{read:true}});

    ctx.body={
        code:200,
        marked_msg_id:id
    };
});

module.exports=router;